Dernière modification : 08/11/2022 à 08:38
TP2 - Tableaux et tris
Table (d’entiers)
table.h
Dans un fichier table.h, créer un type structuré Table avec trois champs :
- le pointeur vers le tableau en mémoire, “data”
- la taille du tableau en mémoire, “size”
- le nombre d’éléments dans la table, “n”
Ajouter une constante RATIO égale à 50.
Déclarer les fonctions suivantes :
Table* new_table(int size);
alloue dynamiquement une nouvelle table, initialise correctement tous les champs et renvoie son adresse ou NULL en cas de problème d’allocation ;void free_table(Table*);
libère la mémoire associée à une table allouée dynamiquement ;void print_table(Table*);
affiche les n éléments d’une table, encadrés par des[]
et séparés par des,
(la table est passée par adresse uniquement pour économiser une copie) ;int is_sorted(Table*);
renvoie 1 si les éléments de la table sont triés par ordre croissant, 0 sinon ;int dicho_search(Table* t,int x);
réalise une recherche dichotomique de l’élément x dans une table triée et renvoie sa position, ou -1 si l’élément n’est pas dans la table (vous pourrez utiliser pour écrire cette fonction une fonction intermédiairedicho_rec()
qui prend plus de paramètres, mais elle ne doit pas apparaitre dans le .h) ;int insert(Table * t, int e);
ajoute e dans une table triée, avec réallocation de la mémoire associée à la table si nécessaire (on choisira alors une nouvelle taille pour que le taux d’occupation soit égal à RATIO), renvoie la position de l’élément ajouté ou -1 si l’ajout n’a pas été possible (erreur d’allocation mémoire) ;int random_inserts(Table* t, int nb);
réalise l’ajout de nb valeur aléatoire dans la table, renvoie le nombre d’ajouts effectués ;void shuffle(Table* t);
mélange le tableau aléatoirement ;
procédure shuffle(tableau T) pour i de 0 à taille(T)-1 # tirer un nombre aléatoire entre 0 et taille(T) r ← random(0,taille(T)) # échanger les valeurs aux positions i et r swap(T[i], T[r])
procédure shuffle(tableau T)
pour i de 0 à taille(T)-1
# tirer un nombre aléatoire entre 0 et taille(T)
r ← random(0,taille(T))
# échanger les valeurs aux positions i et r
swap(T[i], T[r])
int del(Table * t, int e);
enlève e dans une table triée, avec réallocation de la mémoire associée à la table si l’occupation de la table est inférieur à RATIO pourcent (la nouvelle taille devra être l’ancienne divisée par deux si possible, sinon égale exactement au nombre d’éléments), renvoie l’ancienne position de l’élément e ou -1 si deletion impossible (élément non présent) ;- BONUS
int del_mutiple(Table * t, int e);
enlève toutes les occurances de e dans d’une table, renvoie le nombre de délétions effectuées ; - BONUS
int clean(Table * t);
enlève tous les doublons dans une table, renvoie le nombre de délétions effectuées ; void insertion_sort(Table* t);
réalise le tri par insertion de la table t ;
procédure tri_insertion(tableau T) pour i de 1 à taille(T) - 1 # mémoriser T[i] dans x x ← T[i] # décaler les éléments T[0]..T[i-1] qui sont plus grands que x, en partant de T[i-1] j ← i tant que j > 0 et T[j - 1] > x T[j] ← T[j - 1] j ← j - 1 # placer x dans le "trou" laissé par le décalage T[j] ← x
procédure tri_insertion(tableau T)
pour i de 1 à taille(T) - 1
# mémoriser T[i] dans x
x ← T[i]
# décaler les éléments T[0]..T[i-1] qui sont plus grands que x, en partant de T[i-1]
j ← i
tant que j > 0 et T[j - 1] > x
T[j] ← T[j - 1]
j ← j - 1
# placer x dans le "trou" laissé par le décalage
T[j] ← x
void quick_sort(Table* t, int(*pivot)(Table*,int,int));
réalise le tri quicksort en prenant comme fonction de choix de pivot la fonction passée en paramètre ;
partitionner(tableau T, entier premier, entier dernier, entier pivot) échanger T[pivot] et T[premier] # échange le pivot avec le premier du tableau , le pivot devient le premier du tableau pivot ← premier Tant que premier < dernier Tant que T[premier] <= T[pivot] ET premier < Taille(T) premier ← premier + 1 Tant que T[dernier] >= T[pivot] ET dernier > pivot dernier ← dernier - 1 si premier < dernier alors échanger T[premier] et T[dernier] échanger T[dernier] et T[pivot] renvoyer dernier tri_rapide(tableau T, entier premier, entier dernier) si premier < dernier alors pivot ← choix_pivot(T, premier, dernier) pivot ← partitionner(T, premier, dernier, pivot) tri_rapide(T, premier, pivot-1) tri_rapide(T, pivot+1, dernier)
partitionner(tableau T, entier premier, entier dernier, entier pivot)
échanger T[pivot] et T[premier] # échange le pivot avec le premier du tableau , le pivot devient le premier du tableau
pivot ← premier
Tant que premier < dernier
Tant que T[premier] <= T[pivot] ET premier < Taille(T)
premier ← premier + 1
Tant que T[dernier] >= T[pivot] ET dernier > pivot
dernier ← dernier - 1
si premier < dernier alors
échanger T[premier] et T[dernier]
échanger T[dernier] et T[pivot]
renvoyer dernier
tri_rapide(tableau T, entier premier, entier dernier)
si premier < dernier alors
pivot ← choix_pivot(T, premier, dernier)
pivot ← partitionner(T, premier, dernier, pivot)
tri_rapide(T, premier, pivot-1)
tri_rapide(T, pivot+1, dernier)
int pivot_first(Table*, int b, int e);
renvoit b ;int pivot_middle(Table*, int b, int e);
renvoit l’indice du milieu du sous tableau considéré, c’est à dire (e-b)/2+b;int pivot_random(Table*, int b, int e);
renvoit un entier aléatoire entre b et e:w.
table.c et test.c
Dans un fichier table.c, écrivez le code des fonctions et dans un fichier test.c écrivez une fonction main() permettant de tester.
Vous compilerez à l’aide de l’utilitaire make (il faut donc écrire un fichier Makefile).
Comptage
Ajoutez une constante DEBUG et du code dans chacune de vos fonctions : si DEBUG vaut 1, vos fonctions comptent le nombre d’opérations effectués et l’affiche avant de terminer. Sinon rien ne change.
Comparez les valeurs en faisant varier la taille de votre table.